package com.gang.util;


import freemarker.template.Configuration;
import freemarker.template.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class GenerateDocxUtil {
    private static Logger logger = LoggerFactory.getLogger(GenerateDocxUtil.class);
    public static void freemarkerDocxTest(String rootPath, Map<String,Object> dataMap, String docxPath) throws Exception{
        //配置freemarker模板
        Configuration configuration = new Configuration();
        String fileDirectory = rootPath;
        configuration.setDirectoryForTemplateLoading(new File(fileDirectory));
        String temName =  "tem1.xml";
        String docxZipPath = rootPath + "tem1.zip";
        Template template = configuration.getTemplate(temName);

        //通过模板生成的xml临时文件 方法结束后删除该临时文件
        String outFilePath = rootPath + UUID.randomUUID().toString().replace("-","") + ".xml";
        //指定输出word xml文件的路径
        File docXmlFile = new File(outFilePath);
        FileOutputStream fos = new FileOutputStream(docXmlFile);
        Writer out = new BufferedWriter(new OutputStreamWriter(fos),10240);
        template.process(dataMap,out);
        if(out != null){
            out.close();
        }

        //以下代码 主要用来加密已经生成的xml文件，把xml文件正式转换成加密的word文档
        //包装输入流
        ZipInputStream zipInputStream =  wrapZipInputStream(new FileInputStream(new File(docxZipPath)));
        //包装输出流
        ZipOutputStream zipOutputStream =  wrapZipOutputStream(new FileOutputStream(new File(docxPath)));
        //正式加密替换成docx格式文档
        List<String> itemNameList = new ArrayList<>();
        itemNameList.add("word/document.xml");
        //如果需要替换图片添加此行代码，"word/media/image1.png"为解压出来docx模板后，模板中对应图片的完整路径及名称，如果你添加的图片为jpg格式，那么图片名称会是"image1.jpg"或"image1.jpeg"，各位自己视情况修改，如需替换多张图片就举一反三，往list插入多个元素，我相信你们可以理解的
        itemNameList.add("word/media/image1.png");

        List<InputStream> itemInputStreamList = new ArrayList<>();
        itemInputStreamList.add(new FileInputStream(new File(outFilePath)));
        //这里添加你想替换的图片
//        itemInputStreamList.add(new FileInputStream(new File(${图片路径})));

        replaceItemList(zipInputStream, zipOutputStream, itemNameList, itemInputStreamList);
        new File(outFilePath).delete();
        logger.info("Word-docx文档生成完成");
    }

    public static ZipInputStream wrapZipInputStream(InputStream inputStream){
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        return zipInputStream;
    }

    public static ZipOutputStream wrapZipOutputStream(OutputStream outputStream){
        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
        return zipOutputStream;
    }

    public static void replaceItemList(ZipInputStream zipInputStream, ZipOutputStream zipOutputStream, List<String> itemNameList, List<InputStream> itemInputStreamList){
        if(null == zipInputStream){return;}
        if(null == zipOutputStream){return;}
        ZipEntry entryIn;
        try {
            while((entryIn = zipInputStream.getNextEntry())!=null){
                String entryName =  entryIn.getName();
                ZipEntry entryOut = new ZipEntry(entryName);
                zipOutputStream.putNextEntry(entryOut);
                byte [] buf = new byte[8*1024];
                int len;

                if(itemNameList.indexOf(entryName) != -1){
                    // 使用替换流
                    while((len = (itemInputStreamList.get(itemNameList.indexOf(entryName)).read(buf))) > 0) {
                        zipOutputStream.write(buf, 0, len);
                    }
                } else {
                    // 输出普通Zip流
                    while((len = (zipInputStream.read(buf))) > 0) {
                        zipOutputStream.write(buf, 0, len);
                    }
                }
                // 关闭此 entry
                zipOutputStream.closeEntry();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //e.printStackTrace();
            for (InputStream itemInputStream:itemInputStreamList) {
                close(itemInputStream);
            }
            close(zipInputStream);
            close(zipOutputStream);
        }
    }

    private static void close(InputStream inputStream){
        if (null != inputStream){
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static void close(OutputStream outputStream){
        if (null != outputStream){
            try {
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
